﻿using System;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using System.ComponentModel;
using System.Drawing.Design;
using SdmxMl.Common;
using SdmxMl.UiEditors;

namespace SdmxMl.SmsImportCfg
{
    public enum ParentDefinitionMode
    {
        /// <summary>No hierarchy to detect</summary>
        None,
        /// <summary>level index used for defining hierarchy</summary>
        Level,
        /// <summary>Parent Id used for defining hierarchy</summary>
        ParentId,
        /// <summary>As code text size increase it defines hierarchy</summary>
        DeducesFromCodeLen,
        /// <summary>
        /// Parent Id used for defining hierarchy, Level for codelist distribution
        /// Note that level does not represent the hierarchy depth but an attachement 
        /// likked to codelist.
        /// </summary>
        HierarchyParentAndLevel
    }


    public class BaseCfg
    {
        private GroupCfg _groupCfg;
        [Category("Grouping key(if many)")]
        [DescriptionAttribute("Defines name & column of Artefact selection key if many artefacts in excel worksheet" +
            "This information can also be edited manually in the dialog box.")]
        [Browsable(true)]
        public GroupCfg GroupCfg
        {
            get { return _groupCfg; }
            set { _groupCfg = value; }
        }



        private ArtefactCfg _artefactCfg;
        [Category("Artefact Attributes")]
        [DescriptionAttribute("Defines how to import Artefact attributes from Excel Document." +
            "This information can also be edited manually in the dialog box.")]
        [Browsable(true)]
        public ArtefactCfg Artefact
        {
            get { return _artefactCfg; }
            set { _artefactCfg = value; }
        }
        private int _headerRows;
        [Category("Header")]
        [DefaultValue(1)]
        [DescriptionAttribute("Defines how many rows are used for header in Excel Worksheet." +
            "This field is required.")]
        public int HeaderRowCount
        {
            get { return _headerRows; }
            set { _headerRows = value; }
        }

        private bool _allInOneRow;
        [Category("Header")]
        [DefaultValue(false)]
        [DescriptionAttribute("Defines That all codes information are located in a single Excel row. Information separated by return: CHR(10)" +
            "If true, HeaderRowCount will specify the line before these codes.")]
        public bool AllInOneRow
        {
            get { return _allInOneRow; }
            set { _allInOneRow = value; }
        }

        private int _keyCol;
        [Category("Attributes")]
        [DefaultValue(1)]
        [DescriptionAttribute("Defines the column index in the Excel Worksheet where the item key (or code)is given." +
            "This field is required.")]
        public int ColKey
        {
            get { return _keyCol; }
            set { _keyCol = value; }
        }

        private int _keyParentCol;
        [Category("Attributes")]
        [DefaultValue(0)]
        [DescriptionAttribute("Defines the column index in the Excel Worksheet where the item key (or code)is given." +
            "This field is optional. Hierarchy can be deduce if checkbox HasHierarchy is checked")]
        public int ColParentKey
        {
            get { return _keyParentCol; }
            set { _keyParentCol = value; }
        }

        private ParentDefinitionMode _keyParentMode;
        [Category("Attributes")]
        [DefaultValue(ParentDefinitionMode.None)]
        [DescriptionAttribute("Defines the mode of detection of the parent item in case of hierarchy." +
            "1) Level : when the hierarchy level is specified. 2) ParentId is specified. 3) Deduce from code len, determines level according to code length variation.")]
        public ParentDefinitionMode ColParentMode
        {
            get { return _keyParentMode; }
            set { _keyParentMode = value; }
        }

        [Category("Attributes")]
        [DefaultValue(0)]
        [DescriptionAttribute("Defines the column index in the Excel Worksheet where the start validity of item is given." +
            "This field is optional. It is mainly intended for HierarchicalCodelist artefact")]
        public int ColValidFrom { get; set; }

        [Category("Attributes")]
        [DefaultValue(0)]
        [DescriptionAttribute("Defines the column index in the Excel Worksheet where the end validity of item is given." +
            "This field is optional. It is mainly intended for HierarchicalCodelist artefact")]
        public int ColValidTo { get; set; }

        private int[] _nameCols;
        [Category("Attributes")]
        [RefreshProperties(RefreshProperties.Repaint)]
        [Editor(typeof(InternationalizedColLocEditor), typeof(UITypeEditor))]
        [TypeConverter(typeof(DicoColConverter))]
        [DescriptionAttribute("Defines the set of columns index in the Excel Worksheet where the item Name is given in each supported language. " +
            "Sets unavailable languages to zero. ")]
        public virtual int[] NameColumns
        {
            get { return _nameCols; }
            set { _nameCols = value; }
        }


        private int[] _descrCols;
        [Category("Attributes")]
        [RefreshProperties(RefreshProperties.Repaint)]
        [Editor(typeof(InternationalizedColLocEditor), typeof(UITypeEditor))]
        [TypeConverter(typeof(DicoColConverter))]
   //     [Description("Defines Columns location for each supported language. A value of 0 in a column means unused.")]
        [DescriptionAttribute("Defines the set of columns index in the Excel Worksheet where the optional items Description is given in each supported language." +
            " Sets unavailable languages to zero. " )]
        public virtual int[] DescriptionColumns
        {
            get { return _descrCols; }
            set { _descrCols = value; }
        }

        private string _annotType;
        [Category("Attributes")]
        [DefaultValue("")]
        [DescriptionAttribute("Defines the annotation type to use when annotation columns are used")]
        public string AnnotationType
        {
            get { return _annotType; }
            set { _annotType = value; }
        }
        private int[] _abbrevCols;
        [Category("Attributes")]
        [RefreshProperties(RefreshProperties.Repaint)]
        [Editor(typeof(InternationalizedColLocEditor), typeof(UITypeEditor))]
        [TypeConverter(typeof(DicoColConverter))]
        [DescriptionAttribute("Defines the set of columns index in the Excel Worksheet where an optional items Annotation is given in each supported language." +
            "This information is optionnal. Sets all columns to zero if not used")]
        public virtual int[] AnnotationColumns
        {
            get { return _abbrevCols; }
            set { _abbrevCols = value; }
        }

        private int _keyAnnotUrn;
        [Category("Attributes")]
        [DefaultValue(0)]
        [DescriptionAttribute("Defines the column index in the Excel Worksheet where the annotation urn is defined." +
            "This field is optional.")]
        public int ColAnnotationUrn
        {
            get { return _keyAnnotUrn; }
            set { _keyAnnotUrn = value; }
        }
        private int _keyAnnotTitle;
        [Category("Attributes")]
        [DefaultValue(0)]
        [DescriptionAttribute("Defines the column index in the Excel Worksheet where the annotation Title is defined." +
            "This field is optional.")]
        public int ColAnnotationTitle
        {
            get { return _keyAnnotTitle; }
            set { _keyAnnotTitle = value; }
        }


        [Category("Concept")]
        [DefaultValue(0)]
        [DescriptionAttribute("Defines the column index in the Excel Worksheet where the item Text Type is given" +
            "This field is optional and reserved to Concepts. " +
            "Types are:  String, Boolean, Decimal, Float, Double, Integer, BigInteger, Long, Short, " +
            "Duration, DateTime, Time, Date, Year, Month, Day, MonthDay, YearMonth, URI, Timespan, Count, " +
            "InclusiveValueRange, ExclusiveValueRange, Incremental, ObservationalTimePeriod")]
        public virtual int ColTextFormat { get; set; }

        [Category("Concept")]
        [DefaultValue(0)]
        [DescriptionAttribute("Defines the column index in the Excel Worksheet where the item minimal length is given" +
            "This field is optional and reserved to Concepts. ")]
        public virtual int ColTFormatMinLen { get; set; }
        [Category("Concept")]
        [DefaultValue(0)]
        [DescriptionAttribute("Defines the column index in the Excel Worksheet where the item maximum length is given" +
            "This field is optional and reserved to Concepts. ")]
        public virtual int ColTFormatMaxLen { get; set; }
        [Category("Concept")]
        [DefaultValue(0)]
        [DescriptionAttribute("Defines the column index in the Excel Worksheet where the decimal part can be specified for decimal types" +
            "This field is optional and reserved to Concepts. ")]
        public virtual int ColTFormatDecimal { get; set; }

        [Category("Concept")]
        [DefaultValue(0)]
        [DescriptionAttribute("Defines the column index in the Excel Worksheet where the min value can be specified for numeral types" +
            "This field is optional and reserved to Concepts. ")]
        public virtual int ColTFormatMinVal { get; set; }

        [Category("Concept")]
        [DefaultValue(0)]
        [DescriptionAttribute("Defines the column index in the Excel Worksheet where the max value can be specified for numeral types" +
            "This field is optional and reserved to Concepts. ")]
        public virtual int ColTFormatMaxVal { get; set; }

        [Category("Concept")]
        [DefaultValue(0)]
        [DescriptionAttribute("Defines the column index in the Excel Worksheet where the codelist reference is given. "
            + " Codelist ref given as AgencyId+Id+version. IE: ESTAT+CL_FREQ+1.0 ")]
        public virtual int ColCodelistRef { get; set; }
        public BaseCfg()
        {
            _groupCfg = new GroupCfg();
            _artefactCfg = new ArtefactCfg();
            _headerRows = 1;
            _descrCols = new int[LangSupport.Count];
            _abbrevCols = new int[LangSupport.Count];
            _nameCols = DefaultColsNdx(3);
            _keyCol = 1;
            _keyParentMode = ParentDefinitionMode.None;
            _allInOneRow = false;
            _annotType = string.Empty;
            ColValidFrom = ColValidTo = 0;

        }

        public static string DefaultCols(int start)
        {
            StringBuilder sb = new StringBuilder();
            for (int lg = 0; lg < LangSupport.Count; ++lg)
                sb.Append(start == 0 ? start : start + lg).Append(';');
            
            sb.Append("    (");
            foreach (string lg in LangSupport.SupportedLanguages)
                sb.Append(lg).Append(';');
            sb.Append(")");

            
            return sb.ToString();
        }

        public static int [] DefaultColsNdx(int start)
        {
            int[] arr = new int[LangSupport.Count];
            for (int lg = 0; lg < LangSupport.Count; ++lg)
                arr[lg] = (start == 0 ? start : start + lg);
            return arr;
        }

        /// <summary>
        /// Create an instance of this class (or derived) according to XML doc.
        /// </summary>
        /// <param name="reader"> a text reader instance. </param>
        /// <returns> the object instance constructed from xml document</returns>
        public BaseCfg XmlRead(string filepath)
        {
            TextReader reader = null;
            try
            {
                reader = new StreamReader(filepath);

                XmlSerializer xmlSer = new XmlSerializer(this.GetType());
                return xmlSer.Deserialize(reader) as BaseCfg;
            }
            catch (Exception ex)
            {
                throw new ApplicationException("Unable to read. Invalid XML document", ex);
            }
            finally
            {
                if (reader != null)
                    reader.Close();
            }
        }

        /// <summary>
        /// Xml serialization in specified filename
        /// </summary>
        /// <param name="xmlFile"> filename to create</param>
        public virtual void XmlWrite(string xmlFile)
        {
            StreamWriter sw = new StreamWriter(xmlFile);
            XmlWrite(sw);
        }

        /// <summary> XML Persistence using writer. </summary>
        /// <param name="tw"> an object derived from TextWriter</param>
        public virtual void XmlWrite(TextWriter tw)
        {
            try
            {
                XmlSerializer xmlSer = new XmlSerializer(this.GetType());
                xmlSer.Serialize(tw, this);
            }
            finally
            {
                tw.Close();
            }
        }



    }
}
